/**
 * @author  Thomas Lehmann
 * @file    ClassTools.js
 *
 * Copyright (c) 2013 Thomas Lehmann
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
function log(object) {
    if (typeof console.log == 'function') {
        // console.log(object);
    } else {
        document.write(object);
    }
}

function isFunction(functionToCheck) {
    var getType = {};
    return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}

var Class = function (content) {
    var classDefinition = function() {
        this.initialize.apply(this, arguments);
    }

    content["methods"] = function() {
        var entries = new Array();
        for (key in classDefinition.prototype) {
            if (key === "initialize" || key == "methods" || key == "fields") {
                continue;
            }

            if (isFunction(classDefinition.prototype[key])) {
                var instance = this;
                var method   = classDefinition.prototype[key];
                entries.push(method.bind(instance));
            }
        }
        return entries;
    }

    content["fields"] = function() {
        var entries = new Array();
        for (key in this) {
            if (isFunction(this[key])) {
                continue;
            }

            var value = this[key];
            entries[key] = value;
        }
        return entries;
    }

    for (var key in content) {
        classDefinition.prototype[key] = content[key];
    }

    return classDefinition;
}

/**
    @class  Factory
    @brief  allows registering a class defintion by key and
            later on creating class instances by key only.
 */
var Factory = Class({
    // creates container for (key, classDefintions) pairs.
    initialize: function() {
        this.data = new Array();
    },

    // number of registrations
    size: function() {
        return this.data.length;
    },

    /**
        registering a new classDefintion by key. A second
        registration for same key will fail.
        @param key              unique key for a class definition.
        @param classDefinition  a class definition
        @return true when the registration has been done.
     */
    register: function(key, classDefinition) {
        if (!(key in this.data)) {
            this.data[key] = classDefinition;
            return true;
        }
        return false;
    },

    /**
        Creates a instance of a class when found by key with 'new'
        @param key unique key for a class.
        @param 'undefined' if not found other the new instance of a class
     */
    createInstance: function(key) {
        if (key in this.data) {
            return new this.data[key];
        }
        return undefined;
    }
});

if (typeof(exports) != 'undefined') {
    exports.log     = log;
    exports.Class   = Class;
    exports.Factory = Factory;
}

//test();
